<!DOCTYPE html>
          <head>
        <meta charset="utf-8">
            
            <title>
                「Android」Android你可能要用到的自定义View分享 | ttdevs
            </title>
            <meta content="width=device-width, initial-scale=1" name="viewport">
            <meta name="theme-color" content="#4184f3">
            
            
            <link href="/favicon.ico" rel="icon"/>
            

            <link rel="stylesheet" href="/css/highlight.light.css">
            <link rel="stylesheet" href="/css/prism-customize.css">
            <link rel="stylesheet" href="/css/nav-icon.css">
            <link rel="stylesheet" href="/css/waves.min.css">
            <link rel="stylesheet" href="/css/jquery.tocify.css">
            <link rel="stylesheet" href="/css/main.css">
            <link rel="stylesheet" href="/css/nav-indicator.css">
            
  

  
  <!-- 谷歌统计 -->
  <script>
    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

    ga('create', 'UA-97465173-1', 'auto');
    ga('send', 'pageview');

  </script>
  
            </meta>
        </meta>
    </head>

    <body>
        <header>
            <!-- cover image or sth. -->
        </header>
        <div id="main" class="m-scene">
            
<div class="nav-wrapper">

    <div class="container">
        <nav>
            <div class="logo wave">
                <a href="/" id="logo">
                    ttdevs
                </a>
            </div>
            <div class="nav-toggle-icon" >
                <div class="material-hamburger">
                    <span>
                    </span>
                    <span>
                    </span>
                    <span>
                    </span>
                </div>
            </div>
            <div class="menu-wrapper">
                <div class="nav-indicator">
                </div>
                <ul class="menus">
                    
                     
                        <li>
                            <a class="wave " href="/">
                                首页
                            </a>
                        </li>
                     
                        <li>
                            <a class="wave " href="/archives">
                                归档
                            </a>
                        </li>
                     
                        <li>
                            <a class="wave " href="/about">
                                关于
                            </a>
                        </li>
                     
                    
                   
                </ul>
            </div>
        </nav>
    </div>
</div>
            <div class="container content">
                <div class="scene_element scene_element--fadein">
                    <div class="row">
    <div class="main">
        <article>
          
          <header class="post-header with-cover" style="background-image:url('/1970/01/01/[Android]Android你可能要用到的自定义View分享/cover.jpg')" >
          
          </header>
          <h1 class="post-title">「Android」Android你可能要用到的自定义View分享</h1>

          <section class="post-info">
            <span class="post-date">1970/01/01</span>
            
            <span class="post-category">
                <a class="article-category-link" href="/categories/技术/">技术</a>
            </span>
            
            
            <span class="post-tags">
              <ul class="post-tag-list"><li class="post-tag-list-item"><a class="post-tag-list-link" href="/tags/Android/">Android</a></li></ul>
            </span>
            
          </section>

          <section class="post-content">
            <h2 id="0x00-main"><a href="/1970/01/01/[Android]Android你可能要用到的自定义View分享/#0x00-main" class="headerlink" title="0x00 main"></a>0x00 main</h2><p>进步、创新都是在不断变化的需求中诞生的。<br>                        －－ By ttdevs</p>
<p>这不，新的需求又来了。废话不多说，先上设计稿：</p>
<p><img src="http://img.blog.csdn.net/20160619220030319" alt="boohee design"></p>
<p>简单分析上图包括三部分：最上面的类Progressbar，中间两个指示盘和最下面的指示盘。第一个类Progressbar我们项目之前有实现过，但是和这个需求有一些差异，因此决定重新实现一遍。另外两个圆形指示盘本想通过在一张背景图片上放一张指针图，控制指针图的旋转来实现，但是考虑到这样不够灵活，因此也决定自己来画。So，我们接下来实现这三个View。</p>
<p>正式开始之前，先看看我们最终效果图（当然，指针是可以动的）：</p>
<p><img src="http://img.blog.csdn.net/20160629135550259" alt="Indicator view"></p>
<h2 id="0x01-分析"><a href="/1970/01/01/[Android]Android你可能要用到的自定义View分享/#0x01-分析" class="headerlink" title="0x01 分析"></a>0x01 分析</h2><ul>
<li><p>LineIndicator （第一个，类Progressbar）</p>
<p>  主要包括三部分：左侧的提示和内容，右侧的提示和内容，中间的类Progressbar。两侧的文字比较容易处理，掌握了文字的基本绘制，画起来是很容易的。中间的类Progressbar由于打算自己画，所以不会直接贴个Progressbar在上面。我的思路是画一条长的直线作为背景，中间的指示也是直线，比背景直线粗，直线的Paint设置 <code>StrokeCap</code> 为 <code>Paint.Cap.ROUND</code> 即 <code>paint.setStrokeCap(Paint.Cap.ROUND);</code>，这样就可以有两头半圆的效果；中间的指示数字直接画在粗的指示直线上面即可。这里可能遇到的问题有下面两个：</p>
<ul>
<li><p><code>StrokeCap</code> 设置 为 <code>Paint.Cap.ROUND</code>时的位置关系</p>
<p>  <code>StrokeCap</code> 设置 为 <code>Paint.Cap.ROUND</code>，直线两侧的半圆是不算在直线的长度里的。简单来说，如果view的长度和我画的直线长度一致，那么这个直线就是矩形而不是期待的两侧都是半圆的椭圆。</p>
</li>
<li><p>当进度为0或者为100％时的展示</p>
<p>  如果我们背景直线和指示直线起点终点位置一致，那么最终效果就是当进度为0或者100%的时候，指示直线是显示不全的，因此我们需要对这两个位置进行矫正。我的矫正方法比较简单，在0～x和y～100%进度的时候分别显示x和y（本以为自己的思路很屌，后来发现别人也是这么干的）。</p>
</li>
</ul>
</li>
<li><p>CircleIndicator （中间的多种颜色环）</p>
<p>  这个View我将其分解为四部分，从上层到下层：中间指针，刻度环，显示的内容，圆环背景和外层指示文字。每一部分再做分解：</p>
<ul>
<li><p>中间指针</p>
<p>  这个又分解为六个部分：最下层大圆，两个圆形半圆，两个三角形和上层小圆。</p>
</li>
<li><p>刻度环</p>
<p>  由于是圆环，所以必须画弧线了。但是这个弧线又有点特殊，两侧带圆角，中间圆环直角，这个没想到啥好办法，用了很一般的思路：先用 <code>Paint.Cap.ROUND</code> 画两侧的弧，然后 <code>Paint.Style.STROKE</code> 画中间的部分。</p>
</li>
<li><p>显示的内容</p>
<p>  这个就比较简单了，主要在于计算文字的显示位置。</p>
</li>
<li><p>圆环背景和外层文字</p>
<p>  最简单的一个圆，加一个以圆为路径画的文字。</p>
</li>
</ul>
</li>
</ul>
<pre><code>最后我们画的顺序正好与上面所述顺序相反。
</code></pre><ul>
<li><p>ProgressIndicator （最下面的两种颜色环）</p>
<p>  这个相较 CircleIndicator 就简单了一些。在画圆环的时候，我们只需要先画一个灰色背景，然后再画一个绿色圆弧即可。</p>
</li>
</ul>
<h2 id="0x02-实现"><a href="/1970/01/01/[Android]Android你可能要用到的自定义View分享/#0x02-实现" class="headerlink" title="0x02 实现"></a>0x02 实现</h2><p>View的绘制我们应该都比较熟悉，主要有下面三个过程： onMeasure（测量）、onLayout（布局）、onDraw（绘制）。针对上述三个View：LineIndicator，我们根据实际的内容来计算View的高度，宽度用户设定；CircleIndicator和ProgressIndicator的宽度用户设定，高度自定计算与宽度相同。onLayout我们不需要。最后的根据实际的展示内容来绘制。</p>
<p>另外，由于CircleIndicator和ProgressIndicator和相似度高，很多代码可以拿来重用，因此，我写了一个基类来完成公共的部分，特殊部分每个 子类自己完成。最后再子类地onDraw方法中按照顺序调用即可。</p>
<p>由于主要是计算各种坐标位置，代码还是不少的，这里就不贴代码。最后的实现请移步我的 <a href="https://github.com/ttdevs/android/tree/master/modules/indicator" target="_blank" rel="external">github</a>。三个View的代码已经整理完LineIndicator，其它的两个还需要点时间（2016-06-19）。</p>
<h2 id="0x03-知识点"><a href="/1970/01/01/[Android]Android你可能要用到的自定义View分享/#0x03-知识点" class="headerlink" title="0x03 知识点"></a>0x03 知识点</h2><ul>
<li><p>自定义View的思路</p>
<ul>
<li>创建类，继承自View或者ViewGroup或者其它ViewGroup</li>
<li>定义View的可配置参数，如果你需要的话</li>
<li><p>实现View的具体逻辑</p>
<p>这个太粗略了，各位可以参考具体源码。</p>
</li>
</ul>
</li>
<li><p>文字位置的计算</p>
<p>  如果你没有自己画过文字，那你肯定不可能一下子明白文字的画法，或多或少的出现偏移。这里直接给大家推荐一篇讲的非常详细的文章：<a href="http://blog.csdn.net/aigestudio/article/details/41447349" target="_blank" rel="external">http://blog.csdn.net/aigestudio/article/details/41447349</a></p>
</li>
<li><p>位置、半径、弧长等的计算</p>
<p>  这里会涉及到简单的三角函数和圆的周长弧度的计算，可能要说的就是三角函数的参数是弧度制度。</p>
</li>
<li><p>ObjectAnimator</p>
  <figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * 设置内容的颜色值（非resource的id）</div><div class="line"> *</div><div class="line"> * <span class="doctag">@param</span> contentColor 内容的颜色值</div><div class="line"> * <span class="doctag">@param</span> unitColor    单位的颜色值</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setContentColor</span><span class="params">(<span class="keyword">int</span> contentColor, <span class="keyword">int</span> unitColor)</span> </span>&#123;</div><div class="line">    mContentColor = contentColor;</div><div class="line">    mUnitColor = unitColor;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="comment">/**</span></div><div class="line"> * 设置进度</div><div class="line"> *</div><div class="line"> * <span class="doctag">@param</span> indicator 进度值</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setIndicator</span><span class="params">(<span class="keyword">float</span> indicator)</span> </span>&#123;</div><div class="line">    <span class="keyword">if</span> (indicator &lt;= mStartIndicator) &#123;</div><div class="line">        mIndicator = mStartIndicator;</div><div class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (indicator &gt; mEndIndicator) &#123;</div><div class="line">        mIndicator = mEndIndicator;</div><div class="line">    &#125; <span class="keyword">else</span> &#123;</div><div class="line">        mIndicator = indicator;</div><div class="line">    &#125;</div><div class="line">    postInvalidate();</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="comment">/**</span></div><div class="line"> * 获取进度</div><div class="line"> *</div><div class="line"> * <span class="doctag">@return</span> 当前进度值</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">float</span> <span class="title">getIndicator</span><span class="params">()</span> </span>&#123;</div><div class="line">    <span class="keyword">return</span> mStartIndicator;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">animateIndicator</span><span class="params">(<span class="keyword">float</span> indicator)</span> </span>&#123;</div><div class="line">    Interpolator interpolator = <span class="keyword">new</span> AnticipateOvershootInterpolator(<span class="number">1.8f</span>);</div><div class="line">    ObjectAnimator animation = ObjectAnimator.ofFloat(<span class="keyword">this</span>, <span class="string">"indicator"</span>, indicator);</div><div class="line">    animation.setDuration(<span class="number">2000</span>);</div><div class="line">    animation.setInterpolator(interpolator);</div><div class="line">    animation.start();</div><div class="line">&#125;</div></pre></td></tr></table></figure>
</li>
<li><p>处理屏幕的旋转</p>
<p>  由于时间比较紧，这个我还没做。主要在View的以下两个方法中实现：</p>
  <figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="meta">@Override</span></div><div class="line"><span class="function"><span class="keyword">protected</span> Parcelable <span class="title">onSaveInstanceState</span><span class="params">()</span> </span>&#123;</div><div class="line">   <span class="keyword">return</span> <span class="keyword">super</span>.onSaveInstanceState();</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="meta">@Override</span></div><div class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">onRestoreInstanceState</span><span class="params">(Parcelable state)</span> </span>&#123;</div><div class="line">   <span class="keyword">super</span>.onRestoreInstanceState(state);</div><div class="line">&#125;</div></pre></td></tr></table></figure>
</li>
</ul>
<p>最后欢迎各位吐槽并提供更好的建议～～</p>
<p><img src="https://raw.githubusercontent.com/ttdevs/ttdevs.github.io/common/images/logo.png" alt="Create by ttdevs"></p>

          </section>
        </article>
        

       
        <div class="pager">
          
            <a class="post-prev pager-item" href="/1970/01/01/[Android]Android Studio 2.0 NDK开发环境搭建/" >
              <strong class="article-nav-caption">上一篇</strong>
              <p class="post-nav-title">「Android」Android Studio 2.0 NDK开发环境搭建</p>
            </a>
          
          
            <a class="post-next pager-item" href="/1970/01/01/[Android]MediaPlayer单曲循环不卡顿/">
              <strong class="article-nav-caption">下一篇</strong>
              <p class="post-nav-title">「Android」MediaPlayer单曲循环不卡顿</p>
            </a>
          
        </div>
        

         <!-- comments -->
        <div class="comment-section">
  
    


</div>

    </div>
    
    <aside>
        <div id="toc">
        </div>
    </aside>
    
</div>

                </div>
            </div>
        </div>
        <footer class="footer">
    <p>由<a href="http://hexo.io/" target="_blank">Hexo</a>强力驱动，搭载<a href="https://github.com/wayou/hexo-theme-gstyle">gstyle</a>主题</p>
    <p>
        &copy; 2017 ttdevs
    </p>
</footer>
<script src="/lib/jquery.js"></script>
<script src="/lib/waves.js"></script>
<script src="/lib/jquery-ui.js"></script>
<script src="/lib/jquery.tocify.js"></script>
<script src="/js/main.js"></script>

    </body>
</html>
